After asking for
useable CA Software, I have finally settled on using EasyRSA. This is what I did to come across
the packaging shortcomings of EasyRSA in Debian.
Storing your CA
Be sure that your CA is stored in a secure place. Don’t store it online, and make it accessible only to yourself.
In my opinion, storing the the CA in a cryptoloop container file on a small 32 MB USB stick is a good idea. Cryptloop is
rather easy today and available in the stock Linux kernel. I commonly use grml-crypt to manage the crypto loopback
stuff:
sudo grml-crypt start /media/usb4/cryptoloop $MOUNTPOINT
Gotcha: don’t confuse sudo’s “password” prompt with grml-crypt’s “Enter LUKS
passphrase” prompt, the cryptoloop password won’t bring you anywhere on the sudo prompt.
Preparing the CA directory
For the CA, create a dedicated directory in the mounted cryptoloop file system. You’re originally supposed to
copy the entire EasyRSA directory tree in there, but I’d recommend to only link the files from your
system’s EasyRSA directory to automatically take advantage of distribution updates.
You’ll need at least these links:
lrwxrwxrwx 1 mh mh 56 Dec 25 23:23 openssl.cnf -> /usr/share/doc/openvpn/examples/easy-rsa/2.0/openssl.cnf
lrwxrwxrwx 1 mh mh 52 Dec 25 23:22 pkitool -> /usr/share/doc/openvpn/examples/easy-rsa/2.0/pkitool
lrwxrwxrwx 1 mh mh 60 Dec 25 23:23 whichopensslcnf -> /usr/share/doc/openvpn/examples/easy-rsa/2.0/whichopensslcnf
ln -s /usr/share/doc/openvpn/examples/easy-rsa/2.0/openssl.cnf .
ln -s /usr/share/doc/openvpn/examples/easy-rsa/2.0/pkitool .
ln -s /usr/share/doc/openvpn/examples/easy-rsa/2.0/whichopensslcnf .
Configuring your CA
The only thing you cannot link is the vars file which contains your CA’s local settings:
export EASY_RSA=“$(pwd)”
export OPENSSL=“openssl”
export PKCS11TOOL=“pkcs11-tool”
export GREP=“grep”
export KEY_CONFIG=$($EASY_RSA/whichopensslcnf $EASY_RSA)
export KEY_DIR=“$EASY_RSA/keys”
# Issue rm -rf warning
echo NOTE: If you run ./clean-all, I will be doing a rm -rf on $KEY_DIR
export KEY_SIZE=1024
export CA_EXPIRE=3650
export KEY_EXPIRE=3650
export KEY_COUNTRY=“DE”
export KEY_PROVINCE=“”
export KEY_CITY=“”
export KEY_ORG=“Zugschlus.de”
export KEY_EMAIL=“mh+easyrsa-mh-openvpn@zugschlus.de”
export PKCS11_MODULE_PATH=“dummy”
export PKCS11_PIN=“dummy”
Comments have been removed from this file. Better copy the file from /usr/share/doc/openvpn/examples/easy-rsa/2.0/vars
and edit it to your needs. I added the two PKCS11 variables since you won’t otherwise be able to issue
certificate requests.
Creating the CA
Next, decide on a shell instance where you will do most operations, and source vars in there.
Next, run /usr/share/doc/openvpn/examples/easy-rsa/2.0/clean-all. If you do this in a directory of an already-in-use
EasyRSA CA, you’ll need to restore your backup.
To actually initialize the CA, run pkitool --initca --pass. If you do not give the --pass parameter, you’ll
create a CA that can issue certificates without asking for a passphrase, which might not be a brilliant idea. Choose a
reasonably secure pass phrase.
Creating Certificates - the simple and suboptimal way
You can now simply proceed to create an arbitrary number of pairs of “private” keys and associated
certificate by simply calling pkitool <clientname> and/or pkitool --server <servername>. Depending on your
security policy, you can mandate the private keys to be protected by a passphrase (adding --pass to the command lines),
but you’ll have the expense of being asked for the passphrase every time you start a new openvpn daemon.
Creating Certificates the Right Way
I have put the “private” in quotes since the keys created this way are not really private: The key was
created on the box hosting the CA, was stored on the local (crypted) file system and needs to be moved to the target
system via a secure channel. Doing so the right way is harder than expected, so it is usually the better way to keep
the private key really private by creating it directly on the target system. On the target system, you need OpenVPN
installed, and openssl. After the certificate was created, you can remove openssl again.
Creating a private key is part of a key-pair generation process that also leaves a certificate request. The contents of
the certificate request is public, and you can safely move it to the CA box and convert it to a certificate by signing
the request. You only need to make sure that nobody exchanges your target system’s certificate request for her
own before you sign it as you might end up certifying a wrong identity.
For the rest of this document we’re going to assume that you have ssh access to the target system and have
verified the ssh host key, so that you can be reasonably sure to be connected to the right system.
To create a certificate request, you can use this script, which I have called create-easyrsa-cert-req:
#!/bin/bash
set -u
TMPDIR=“/tmp”
export OPENSSL=“openssl”
export PKCS11TOOL=“pkcs11-tool”
export GREP=“grep”
export KEY_CONFIG=“/usr/share/doc/openvpn/examples/easy-rsa/2.0/openssl.cnf”
export KEY_DIR=“$TMPDIR/keys.$$”
mkdir -p $KEY_DIR
export KEY_SIZE=1024
export KEY_EXPIRE=3650
export KEY_COUNTRY=“DE”
export KEY_PROVINCE=“”
export KEY_CITY=“”
export KEY_ORG=“Zugschlus”
export KEY_OU=“$(hostname --fqdn)”
export KEY_EMAIL=“mh+$(hostname)-ovpn-cert@zugschlus.de”
export DEBUG=1
umask 077
if [ “$ 1:-foo ” != “server” ]; then
/usr/share/doc/openvpn/examples/easy-rsa/2.0/pkitool --csr $(hostname)
else
/usr/share/doc/openvpn/examples/easy-rsa/2.0/pkitool --csr --server $(hostname)
fi
mv $TMPDIR/keys.$$/* .
rm -rf $TMPDIR/keys.$$
When called without parameters, it creates a certificate request for an OpenVPN client certificate, and when you call
it with “server” as parameter, it will create a server certificate request.
In any case, it will leave two files in the current directory. They are named after the current host name, and have the
extensions .csr and .key. The .key file is your private key. keep it private! The .csr file is the certificate request
which you can now move to the keys subdirectory of your CA directory via scp or other means such as an USB stick.
To do the actual signing, invoke pkitool --sign <hostname> and enter the CA passphrase. You can ignore the error
message that there was no .key file to chmod. Gotcha, when signing a server certificate, use pkitool --server --sign
<hostname>.
Move Certificate to the target host
You can now move the certificate to the target system. Since you’re probably going to need the root certificate
and the certificate revocation list as well, you can move the .key file (if created on the CA system), the .crt file,
and ca.crt to the target system. These files are public, so there is no need for a secure channel.
Revoking Certificates
Since an OpenVPN server’s only means of authentication is to check whether the certificate presented by a client
is signed by the “right” CA, the only way to revoke VPN access is to revoke the certificate. This is also
done on the CA system by calling /usr/share/doc/openvpn/examples/easy-rsa/2.0/revoke-full <client-name>. This
creates a crl.pem file which contains a list of all revoked certificates. You need to have a mechanism to distribute
that list to all systems that might need it, and it is recommended to have this automated. Remember, if you do not
distribute the .crl file, the systems are not going to know about revoked certificates.